#include "lxz_config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lxz_types.h"
#include "os_port.h"
#include "lxz_runlog.h"
#include "lxz_debug.h"
#include "lxz_ring.h"
#include "lxz_string.h"
#include "lxz_dstring.h"
#include "lxz_atc_req.h"
#include "lxz_sgcc_cmd.h"
#include "lxz_urc_table.h"
#include "lxz_spcomm.h"

#include "lxz_dbg_vmem.h"

/*urc future process*/

static sint32 lxzurc_callback_f_default(void * pctxt);
static sint32 lxzurc_callback_f_dollar_myurcready(void * pctxt);
static sint32 lxzurc_callback_f_dollar_myurctime(void * pctxt);
static sint32 lxzat_task_f_DoTask(lxzat_task_t *p_dst_task);

static sint32 gs_nb_tasks = 0;

/*
 *  Description:
 *    A caplets for hiding concrete implementation.
 *  Note:
 *    Please do not change any part of current piece when you unsure.
 */
const lxzurc_info_t urc_info_plus_cmti =
{
    "+CMTI", 
    lxzurc_callback_f_default,
};

/*
 *  Description:
 *    A caplets for hiding concrete implementation.
 *  Note:
 *    Please do not change any part of current piece when you unsure.
 */
const lxzurc_info_t urc_info_plus_cmt =
{
    "+CMT:", 
    lxzurc_callback_f_default,
};

/*
 *  Description:
 *    A caplets for hiding concrete implementation.
 *  Note:
 *    Please do not change any part of current piece when you unsure.
 */
const lxzurc_info_t urc_info_plus_cds =
{
    "+CDS", 
    lxzurc_callback_f_default,
};

/*
 *  Description:
 *    A caplets for hiding concrete implementation.
 *  Note:
 *    Please do not change any part of current piece when you unsure.
 */
const lxzurc_info_t urc_info_plus_cbm =
{
    "+CBM", 
    lxzurc_callback_f_default,
};

/*
 *  Description:
 *    A caplets for hiding concrete implementation.
 *  Note:
 *    Please do not change any part of current piece when you unsure.
 */
const lxzurc_info_t urc_info_plus_creg =
{
    "+CREG", 
    lxzurc_callback_f_default,
};

/*
 *  Description:
 *    A caplets for hiding concrete implementation.
 *  Note:
 *    Please do not change any part of current piece when you unsure.
 */
const lxzurc_info_t urc_info_plus_cgreg =
{
    "+CGREG", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_rssi =
{
    "^RSSI", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_cerssi =
{
    "^CERSSI", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_ccallstate =
{
    "^CCALLSTATE", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_orig =
{
    "^ORIG", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_conf =
{
    "^CONF", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_conn =
{
    "^CONN", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_caret_cend =
{
    "^CEND", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_null_ring =
{
    "RING", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_null_busy =
{
    "BUSY", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_null_connect =
{
    "CONNECT", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_null_no_answer =
{
    "NO ANSWER", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_null_no_carrier =
{
    "NO CARRIER", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_null_no_dialtone =
{
    "NO DAILTONE", 
    lxzurc_callback_f_default,
};

const lxzurc_info_t urc_info_dollar_myurcready =
{
    "$MYURCREADY", 
    lxzurc_callback_f_dollar_myurcready,
};

const lxzurc_info_t urc_info_dollar_myurctime =
{
    "$MYURCTIME", 
    lxzurc_callback_f_dollar_myurctime,
};

static const lxzurc_info_t * gs_urc_info_table[] =
{
    &urc_info_plus_cmti,
    &urc_info_plus_cmt,
    &urc_info_plus_cds,
    &urc_info_plus_cbm,
    &urc_info_plus_creg,
    &urc_info_plus_cgreg,
    &urc_info_dollar_myurcready,
    &urc_info_dollar_myurctime,
#if 0
    &urc_info_caret_rssi,
    &urc_info_caret_cerssi,
    &urc_info_caret_ccallstate,
    &urc_info_caret_orig,
    &urc_info_caret_conf,
    &urc_info_caret_conn,
    &urc_info_caret_cend,
    &urc_info_null_ring,
    &urc_info_null_busy,
    &urc_info_null_connect,
    &urc_info_null_no_answer,
    &urc_info_null_no_carrier,
    &urc_info_null_no_dialtone,
#endif
    NULL
}
;

lxzat_task_t *p_head_task = NULL;
lxzat_task_t *p_tail_task = NULL;

static sint32 lxzurc_callback_f_default(void * pctxt)
{
    uint32 i_op_status = 0;
    sint32 i_vsp_id = 0;
    while(i_vsp_id < LXZAT_MAX_VSP_NUM)
    {
        lxzat_urc_f_printf(i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s", (uint08 *)pctxt);
        i_vsp_id++;
    }
    i_op_status = 1;
    return i_op_status;
}


static sint32 lxzurc_callback_f_dollar_myurcready(void * pctxt)
{
    uint32 i_op_status = 0;
    i_op_status = 1;
    return i_op_status;
}

static sint32 lxzurc_callback_f_dollar_myurctime(void * pctxt)
{
    uint32 i_op_status = 0;

    uint32 i_cur_year = 0;
    uint32 i_cur_month = 0;
    uint32 i_cur_day = 0;
    uint32 i_cur_hour = 0;
    uint32 i_cur_minute = 0;
    uint32 i_cur_second = 0;
    uint32 i_cur_prechar = 0;
    uint32 i_cur_timezone = 0;
    uint32 i_cur_dt = 0;
    uint08 u_shcmd_buf[100];

    sscanf(pctxt,"^TIME: \"%d/%d/%d,%d:%d:%d%c%d,%d\"", &i_cur_year, &i_cur_month, &i_cur_day,
        &i_cur_hour, &i_cur_minute, &i_cur_second, &i_cur_prechar, &i_cur_timezone, &i_cur_dt);

    i_cur_year = i_cur_year + 2000;
    memset(u_shcmd_buf, 0, sizeof(u_shcmd_buf));
    sprintf(u_shcmd_buf, "busybox date -s \"%d.%d.%d-%d:%d:%d\"", i_cur_year, i_cur_month, i_cur_day,
        i_cur_hour, i_cur_minute, i_cur_second);
    system(u_shcmd_buf);

    i_op_status = 1;

    return i_op_status;
}

/*
 *  Description:
 *    Get an urc-information descriptor.
 *  Param: i_index_id, a specified index
 *  Return: an urc-information descriptor;
 */
const lxzurc_info_t * lxzurc_info_f_get(sint32 i_index_id)
{
    sint32 i_ai_num = 0;

    i_ai_num = sizeof(gs_urc_info_table)/sizeof(gs_urc_info_table[0]);
    if (i_index_id < i_ai_num)
    {
        return gs_urc_info_table[i_index_id];
    }
    
    return NULL;
}

/*
 *  Description:
 *    Insert a task into task-list.
 *  Param: p_new_task, the task that will be inserted.
 *  Return: i_op_status, 0, fail;1, success.
 */
sint32 lxzat_task_f_create(lxzat_task_t * p_new_task)
{
	sint32 i_op_status = 0;

    if (p_new_task != NULL)
	{
		p_new_task->next = p_head_task;
		p_head_task = p_new_task;
	}

    OS_DBG_LOG(("lxzat:lxzat_task_f_create,taskID:0x%08X,OK\r\n", p_new_task));
    gs_nb_tasks = gs_nb_tasks + 1;
    OS_DBG_LOG(("lxzat:Cycle-checking:i_nb_tasks=%d\r\n", gs_nb_tasks));

	i_op_status = 1;
	return i_op_status;
}

/*
 *  Description:
 *    Remove the specified task from task-list.
 *  Param: p_dst_task, the task that will be removed.
 *  Return: i_op_status, 0, fail;1, success.
 */
sint32 lxzat_task_f_destroy(lxzat_task_t * p_dst_task)
{
	sint32 i_op_status = 0;
	lxzat_task_t *p_cur_task = NULL;
	lxzat_task_t *p_pre_task = NULL;

	p_cur_task = p_head_task;
	while(p_cur_task != NULL)
	{
		if(p_cur_task == p_dst_task)
		{
			if(p_cur_task == p_head_task)
			{
				p_head_task = p_head_task->next;
			}
			else
			{
				p_pre_task->next = p_cur_task->next;
			}

            p_cur_task->fp_exit(p_cur_task->sparam1, p_cur_task->sparam2);
            free(p_cur_task);

            OS_DBG_LOG(("lxzat:lxzat_task_f_destroy,taskID:0x%08X,OK\r\n", p_dst_task));
            gs_nb_tasks = gs_nb_tasks - 1;
            OS_DBG_LOG(("lxzat:Cycle-checking:i_nb_tasks=%d\r\n", gs_nb_tasks));

			i_op_status = 1;
			break;
		}

        p_pre_task = p_cur_task;
        p_cur_task = p_cur_task->next;
	}	
	return i_op_status;
}

/*
 *  Description:
 *    Destroy all tasks that included in task-list.
 *  Param: NONE
 *  Return: i_op_status, 0, fail;1, success.
 */
sint32 lxzat_task_f_destroyall(void)
{
    sint32 i_op_status = 1;

    lxzat_task_t * p_cur_task = NULL;
    lxzat_task_t * p_nxt_task = NULL;

    p_cur_task = p_head_task;
    while(p_cur_task != NULL)
    {
        p_nxt_task = p_cur_task->next;
        lxzat_task_f_destroy(p_cur_task);
        p_cur_task = p_nxt_task;
    }

	return i_op_status;
}

/*
 *  Description:
 *    Execute a specified task.
 *  Param: p_dst_task, the task that will be executed.
 *  Return: i_op_status: 1,;
 */
static sint32 lxzat_task_f_DoTask(lxzat_task_t *p_dst_task)
{
	sint32 i_op_status = 0;

    if (   (p_dst_task != NULL)
        && (p_dst_task->fp_exec != NULL))
    {
        i_op_status = p_dst_task->fp_exec(p_dst_task->sparam1, p_dst_task->sparam2);
    }

    return i_op_status;
}

/*
 *  Description:
 *    All tasks that included in list should be done one time in a cycle.
 *  Param: NONE
 *  Return: NONE;
 */
void lxzat_task_f_DoCycle(void)
{
	sint32 i_op_status = 0;
	lxzat_task_t *p_nxt_task = NULL;
	lxzat_task_t *p_cur_task = NULL;
	p_cur_task = p_head_task;
	while(p_cur_task != NULL)
	{
		p_nxt_task = p_cur_task->next;

        i_op_status = lxzat_task_f_DoTask(p_cur_task);
        if(i_op_status == 0)
        {
            lxzat_task_f_destroy(p_cur_task);
        }

        p_cur_task = p_nxt_task;
	}
}


